package com.fw.service.file.impl;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;

import com.fw.service.applicationlog.ApplicationLogService;
import com.fw.service.applicationlog.bean.ApplicationLogBean;
import com.fw.service.bean.SearchCriteriaBean;
import com.fw.service.bean.SearchResultBean;
import com.fw.service.file.FileService;
import com.fw.service.file.bean.FileBean;
import com.fw.service.file.bean.SearchFileBean;
import com.fw.service.persistence.dao.FilesDAO;
import com.fw.service.persistence.dto.Files;
import com.fw.service.property.PropertyService;
import com.fw.util.DateUtils;
import com.fw.util.PageRequestUtils;
import com.fw.util.StringUtils;

public class FileServiceImpl implements FileService {

    @Autowired
    private PropertyService propertyService;
    @Autowired
    private ApplicationLogService applicationLogService;
    @Autowired
    private FilesDAO filesDAO;

    private static final List<String> CONTENT_TYPE_IMAGE = new ArrayList<String>();
    private static final List<String> CONTENT_TYPE_PDF = new ArrayList<String>();
    private static final List<String> CONTENT_TYPE_TEXT = new ArrayList<String>();
    private static final List<String> CONTENT_TYPE_EXCEL = new ArrayList<String>();
    private static final List<String> CONTENT_TYPE_CSV = new ArrayList<String>();
    private static final List<String> CONTENT_TYPE_DOC = new ArrayList<String>();
    private static final List<String> CONTENT_TYPE_XML = new ArrayList<String>();

    public FileBean saveFile(String filename, String contentType, byte[] content, String description) {
	String clazz = FileService.class.getName();
	String method = "saveFile";
	String filePathStr = null;
	try {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_INFO);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(method);
	    applicationLogService.createApplicationLog(applicationLogBean);

	    DateFormat dateFormat = new SimpleDateFormat(StringUtils.PATTERN_DATETIME_PERSISTENCE);
	    String createDateTime = dateFormat.format(new Date());

	    Files fileUpload = new Files();
	    fileUpload.setContentType(contentType);
	    fileUpload.setCreateDateTime(createDateTime);
	    fileUpload.setDescription(description);
	    fileUpload.setFilename(filename);

	    String path = this.getFilePath(contentType);
	    filePathStr = path + "/" + filename;
	    java.io.File filePath = new java.io.File(filePathStr);
	    FileUtils.writeByteArrayToFile(filePath, content);
	    Long fileSize = FileUtils.sizeOf(filePath);
	    fileUpload.setFileSize(fileSize);

	    Files fileSaved = filesDAO.save(fileUpload);
	    if (fileSaved != null && fileSaved.getId() != null) {
		FileBean fileBean = new FileBean();
		fileBean.setId(fileSaved.getId());
		fileBean.setContentType(fileSaved.getContentType());
		fileBean.setCreateDateTime(fileSaved.getCreateDateTime());
		fileBean.setDescription(fileSaved.getDescription());
		fileBean.setFilename(fileSaved.getFilename());
		fileBean.setFileSize(fileSaved.getFileSize());
		byte[] contentByteArry = FileUtils.readFileToByteArray(filePath);
		fileBean.setContent(contentByteArry);
		return fileBean;
	    } else {
		if (filePath.exists()) {
		    FileUtils.forceDelete(filePath);
		}
	    }
	} catch (Exception e) {
	    java.io.File filePath = new java.io.File(filePathStr);
	    if (filePath.exists()) {
		try {
		    FileUtils.forceDelete(filePath);
		} catch (IOException e1) {
		}
	    }
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return null;
    }

    @Override
    public FileBean saveFileAndGenerateFilename(String fileExtension, String contentType, byte[] content, String description) {
	String filenameGenerate = this.generateFilename(contentType);
	String filename = filenameGenerate + "." + fileExtension;
	FileBean fileBean = this.saveFile(filename, contentType, content, description);
	return fileBean;
    }

    @Override
    public FileBean getFile(Long id) {
	String clazz = FileService.class.getName();
	String method = "getFile";
	try {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_INFO);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(method);
	    applicationLogService.createApplicationLog(applicationLogBean);
	    Files file = filesDAO.findOne(id);
	    if (file != null) {
		FileBean fileBean = new FileBean();
		fileBean.setId(file.getId());
		fileBean.setContentType(file.getContentType());
		fileBean.setCreateDateTime(file.getCreateDateTime());
		fileBean.setDescription(file.getDescription());
		fileBean.setFilename(file.getFilename());
		fileBean.setFileSize(file.getFileSize());
		String path = this.getFilePath(file.getContentType());
		java.io.File filePath = new java.io.File(path + "/" + file.getFilename());
		byte[] contentByteArry = FileUtils.readFileToByteArray(filePath);
		fileBean.setContent(contentByteArry);
		return fileBean;
	    }
	} catch (Exception e) {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return null;
    }

    @Override
    public Boolean deleteFile(Long id) {
	String clazz = FileService.class.getName();
	String method = "saveFile";
	try {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_INFO);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(method);
	    applicationLogService.createApplicationLog(applicationLogBean);
	    Files file = filesDAO.findOne(id);
	    if (file != null) {
		String path = this.getFilePath(file.getContentType());
		java.io.File filePath = new java.io.File(path + "/" + file.getFilename());
		if (filePath.exists()) {
		    FileUtils.forceDelete(filePath);
		}
		filesDAO.delete(file);
		return true;
	    }
	} catch (Exception e) {
	    e.printStackTrace();
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return null;
    }

    @Override
    public SearchResultBean<FileBean> searchFile(SearchCriteriaBean<SearchFileBean> searchCriteriaBean) {
	SearchResultBean<FileBean> searchResultBean = null;
	String clazz = FileService.class.getName();
	String method = "saveFile";
	try {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_INFO);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(method);
	    applicationLogService.createApplicationLog(applicationLogBean);

	    SearchFileBean searchFileBean = searchCriteriaBean.getCriteriaBean();

	    final String filename = searchFileBean.getFilename();
	    final String description = searchFileBean.getDescription();
	    final String contentType = searchFileBean.getContentType();
	    final Long minSize = searchFileBean.getFileSizeMin();
	    final Long maxSize = searchFileBean.getFileSizeMax();
	    final Date createDateFrom = searchFileBean.getCreateDateFrom();
	    final Date createDateTo = searchFileBean.getCreateDateTo();

	    Specification<Files> specification = new Specification<Files>() {
		@Override
		public Predicate toPredicate(Root<Files> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
		    List<Predicate> predicates = new ArrayList<Predicate>();
		    if (filename != null && !filename.isEmpty()) {
			predicates.add(cb.like(root.<String> get("filename"), "%" + filename + "%"));
		    }
		    if (description != null && !description.isEmpty()) {
			predicates.add(cb.like(root.<String> get("description"), "%" + description + "%"));
		    }
		    if (contentType != null && !contentType.isEmpty()) {
			predicates.add(cb.like(root.<String> get("employeeID"), "%" + contentType + "%"));
		    }
		    if (minSize != null) {
			predicates.add(cb.greaterThanOrEqualTo(root.<Long> get("fileSize"), minSize));
		    }
		    if (maxSize != null) {
			predicates.add(cb.lessThanOrEqualTo(root.<Long> get("fileSize"), maxSize));
		    }
		    if (createDateFrom != null) {
			predicates.add(cb.greaterThanOrEqualTo(root.<Date> get("createDatetime"), DateUtils.getFromDate(createDateFrom)));
		    }
		    if (createDateTo != null) {
			predicates.add(cb.lessThanOrEqualTo(root.<Date> get("createDatetime"), DateUtils.getToDate(createDateTo)));
		    }
		    Predicate result = cb.conjunction();
		    for (Predicate predicate : predicates) {
			result.getExpressions().add(predicate);
		    }
		    return result;
		}
	    };

	    Page<Files> page = filesDAO.findAll(specification, PageRequestUtils.getPageRequest(searchCriteriaBean));
	    if (page != null) {
		searchResultBean = new SearchResultBean<FileBean>();
		searchResultBean.setTotalElements(page.getTotalElements());
		searchResultBean.setTotalPages(page.getTotalPages());
		List<FileBean> content = new ArrayList<FileBean>();
		List<Files> files = page.getContent();
		if (files != null && !files.isEmpty()) {
		    for (Files file : files) {
			FileBean fileBean = new FileBean();
			fileBean.setId(file.getId());
			fileBean.setContentType(file.getContentType());
			fileBean.setCreateDateTime(file.getCreateDateTime());
			fileBean.setDescription(file.getDescription());
			fileBean.setFilename(file.getFilename());
			fileBean.setFileSize(file.getFileSize());
			content.add(fileBean);
		    }
		}
		searchResultBean.setContent(content);
	    }
	} catch (Exception e) {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return null;
    }

    private String getFilePath(String contentType) {
	if (CONTENT_TYPE_IMAGE.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.image");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_IMAGE.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_PDF.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.pdf");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_PDF.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_TEXT.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.text");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_TEXT.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_EXCEL.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.excel");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_EXCEL.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_CSV.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.csv");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_CSV.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_DOC.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.doc");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_DOC.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_XML.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.xml");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_XML.add(str.trim());
		}
	    }
	}
	String path = null;
	if (CONTENT_TYPE_IMAGE.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.image");
	} else if (CONTENT_TYPE_PDF.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.pdf");
	} else if (CONTENT_TYPE_TEXT.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.text");
	} else if (CONTENT_TYPE_EXCEL.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.excel");
	} else if (CONTENT_TYPE_CSV.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.csv");
	} else if (CONTENT_TYPE_DOC.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.doc");
	} else if (CONTENT_TYPE_XML.contains(contentType)) {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.xml");
	} else {
	    path = propertyService.getProperty("com.fw.service.file.FileService.storePath.temp");
	}
	java.io.File file = new java.io.File(path);
	if (!file.exists()) {
	    file.mkdirs();
	}
	return path;
    }

    private String generateFilename(String contentType) {
	if (CONTENT_TYPE_IMAGE.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.image");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_IMAGE.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_PDF.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.pdf");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_PDF.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_TEXT.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.text");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_TEXT.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_EXCEL.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.excel");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_EXCEL.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_CSV.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.csv");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_CSV.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_DOC.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.doc");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_DOC.add(str.trim());
		}
	    }
	}
	if (CONTENT_TYPE_XML.isEmpty()) {
	    String contentTypeStr = propertyService.getProperty("com.fw.service.file.FileService.contentType.xml");
	    if (contentTypeStr != null) {
		String[] strArr = contentTypeStr.split(",");
		for (String str : strArr) {
		    CONTENT_TYPE_XML.add(str.trim());
		}
	    }
	}
	String perfix = null;
	if (CONTENT_TYPE_IMAGE.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.image");
	} else if (CONTENT_TYPE_PDF.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.pdf");
	} else if (CONTENT_TYPE_TEXT.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.text");
	} else if (CONTENT_TYPE_EXCEL.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.excel");
	} else if (CONTENT_TYPE_CSV.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.csv");
	} else if (CONTENT_TYPE_DOC.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.doc");
	} else if (CONTENT_TYPE_XML.contains(contentType)) {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.xml");
	} else {
	    perfix = propertyService.getProperty("com.fw.service.file.FileService.filename.prefix.temp");
	}
	Long datetime = new Date().getTime();
	String filename = perfix + "" + datetime;
	return filename;
    }

}
